aboutsummaryrefslogtreecommitdiffstats
path: root/apps/mobile/app/dashboard/lists/[slug].tsx
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-11-23 12:25:56 +0000
committerGitHub <noreply@github.com>2025-11-23 12:25:56 +0000
commitc5c71ba9507f1c739773cf2677c53f83d29300bc (patch)
tree6c106e52a6bfda1d9289a738a00dacfc5934f4e3 /apps/mobile/app/dashboard/lists/[slug].tsx
parent8a5a109cdf14b6503b6bd07aa667788924a12fe6 (diff)
downloadkarakeep-c5c71ba9507f1c739773cf2677c53f83d29300bc.tar.zst
feat(mobile): proper handling for shared list permissions (#2165)
* feat(mobile): Restrict bookmark editing in shared lists Apply the same ownership-based restrictions that exist in the web app to the mobile app. Users can now only edit, delete, and manage their own bookmarks, even when viewing them in shared lists. Changes: - BottomActions: Hide edit actions (lists, tags, info, delete) for non-owners - BookmarkCard: Hide favorite button and action menu for non-owners - Info page: Make title, notes, tags, and lists read-only for non-owners - NotePreview: Hide "Edit Notes" button for non-owners All restrictions are based on comparing the current user ID (from useWhoAmI) with the bookmark's userId field. * some fixes * make tags non clickable for collaborators * add leave list --------- Co-authored-by: Claude <noreply@anthropic.com>
Diffstat (limited to 'apps/mobile/app/dashboard/lists/[slug].tsx')
-rw-r--r--apps/mobile/app/dashboard/lists/[slug].tsx49
1 files changed, 45 insertions, 4 deletions
diff --git a/apps/mobile/app/dashboard/lists/[slug].tsx b/apps/mobile/app/dashboard/lists/[slug].tsx
index f98dd6d3..e7aab443 100644
--- a/apps/mobile/app/dashboard/lists/[slug].tsx
+++ b/apps/mobile/app/dashboard/lists/[slug].tsx
@@ -9,6 +9,8 @@ import { api } from "@/lib/trpc";
import { MenuView } from "@react-native-menu/menu";
import { Ellipsis } from "lucide-react-native";
+import { ZBookmarkList } from "@karakeep/shared/types/lists";
+
export default function ListView() {
const { slug } = useLocalSearchParams();
if (typeof slug !== "string") {
@@ -27,7 +29,9 @@ export default function ListView() {
headerTitle: list ? `${list.icon} ${list.name}` : "",
headerBackTitle: "Back",
headerLargeTitle: true,
- headerRight: () => <ListActionsMenu listId={slug} />,
+ headerRight: () => (
+ <ListActionsMenu listId={slug} role={list?.userRole ?? "viewer"} />
+ ),
}}
/>
{error ? (
@@ -47,8 +51,20 @@ export default function ListView() {
);
}
-function ListActionsMenu({ listId }: { listId: string }) {
- const { mutate } = api.lists.delete.useMutation({
+function ListActionsMenu({
+ listId,
+ role,
+}: {
+ listId: string;
+ role: ZBookmarkList["userRole"];
+}) {
+ const { mutate: deleteList } = api.lists.delete.useMutation({
+ onSuccess: () => {
+ router.replace("/dashboard/lists");
+ },
+ });
+
+ const { mutate: leaveList } = api.lists.leaveList.useMutation({
onSuccess: () => {
router.replace("/dashboard/lists");
},
@@ -60,7 +76,20 @@ function ListActionsMenu({ listId }: { listId: string }) {
{
text: "Delete",
onPress: () => {
- mutate({ listId });
+ deleteList({ listId });
+ },
+ style: "destructive",
+ },
+ ]);
+ };
+
+ const handleLeave = () => {
+ Alert.alert("Leave List", "Are you sure you want to leave this list?", [
+ { text: "Cancel", style: "cancel" },
+ {
+ text: "Leave",
+ onPress: () => {
+ leaveList({ listId });
},
style: "destructive",
},
@@ -75,16 +104,28 @@ function ListActionsMenu({ listId }: { listId: string }) {
title: "Delete List",
attributes: {
destructive: true,
+ hidden: role !== "owner",
},
image: Platform.select({
ios: "trash",
}),
},
+ {
+ id: "leave",
+ title: "Leave List",
+ attributes: {
+ destructive: true,
+ hidden: role === "owner",
+ },
+ },
]}
onPressAction={({ nativeEvent }) => {
if (nativeEvent.event === "delete") {
handleDelete();
}
+ if (nativeEvent.event === "leave") {
+ handleLeave();
+ }
}}
shouldOpenOnLongPress={false}
>